//
// Created by pzw on 23-12-29.
//

#include "OpenCan.h"
#include <iostream>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QComboBox>
#include <thread>

//接口卡类型定义
#define USBCAN1 3
#define USBCAN2 4
//函数调用返回状态值
#define STATUS_OK 1
#define STATUS_ERR 0

//通道号 @{
#define CAN1 0
#define CAN2 1
// @}

static DWORD DeviceType = USBCAN2; //设备类型 USBCAN2 双通道
static DWORD DeviceInd = 0; //设备索引 0，只有一个 USBCAN

OpenCan::~OpenCan() {
    CloseDevice(DeviceType, DeviceInd);
}

OpenCan::OpenCan(QWidget *parent, QFlags<Qt::WindowType> name) : QMainWindow(parent, name) {
    this->setWindowTitle("OpenCan");

    std::locale::global(std::locale("")); // 设置全局的本地化环境
    std::cout.imbue(std::locale()); // 将 std::cout 的本地化环境设置为全局的本地化环境

    // 创建主窗口
    QWidget *centralWidget = new QWidget(this);
    setCentralWidget(centralWidget);

    // 创建布局
    QVBoxLayout *layout = new QVBoxLayout(centralWidget);

    // 创建打开设备按钮
    QPushButton *openDeviceButton = new QPushButton("打开设备", centralWidget);
    layout->addWidget(openDeviceButton);

    // 创建模式选择下拉框
    QLabel *modeLabel = new QLabel("模式选择:", centralWidget);
    QComboBox *modeComboBox = new QComboBox(centralWidget);
    QStringList modeList = {"正常模式", "只听模式", "自发自收"};
    modeComboBox->addItems(modeList);
    layout->addWidget(modeLabel);
    layout->addWidget(modeComboBox);

    // 创建波特率选择下拉框
    QLabel *baudRateLabel = new QLabel("波特率选择:", centralWidget);
    QComboBox *baudRateComboBox = new QComboBox(centralWidget);
    QStringList baudRateList = {"1000k", "800k", "666k", "500k", "400k", "250k", "200k", "125k", "100k"};
    baudRateComboBox->addItems(baudRateList);
    layout->addWidget(baudRateLabel);
    layout->addWidget(baudRateComboBox);

    // 创建打开失败提示框
    QLabel *errorLabel = new QLabel("打开设备失败", centralWidget);
    errorLabel->setVisible(false);
    errorLabel->setStyleSheet("color: red;");
    layout->addWidget(errorLabel);
    this->errorLabel = errorLabel;

    // 模式选择下拉框的当前索引变化事件
    connect(
            modeComboBox,
            QOverload<int>::of(&QComboBox::currentIndexChanged),
            this,
            [this, modeComboBox]() {
                if (modeComboBox->currentIndex() == 0) {
                    this->openCanMode = 0;
                } else if (modeComboBox->currentIndex() == 1) {
                    this->openCanMode = 1;
                } else if (modeComboBox->currentIndex() == 2) {
                    this->openCanMode = 2;
                } else {
                    this->openCanMode = 0;
                }
                std::cout << "选择打开CAN模式: " << (int) openCanMode << std::endl;
            }
    );

    // 连接波特率选择下拉框的当前索引变化事件
    connect(
            baudRateComboBox,
            QOverload<int>::of(&QComboBox::currentIndexChanged),
            this,
            [this, baudRateLabel, baudRateComboBox]() {
                // 获取选中的波特率
                QString selectedBaudRate = baudRateComboBox->currentText();
                // 显示选中的波特率到QLabel
                baudRateLabel->setText("波特率选择: " + selectedBaudRate);
                if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "1000k")) {
                    this->baudRate0 = 0x00;
                    this->baudRate1 = 0x14;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "800k")) {
                    this->baudRate0 = 0x00;
                    this->baudRate1 = 0x16;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "666k")) {
                    this->baudRate0 = 0x80;
                    this->baudRate1 = 0xB6;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "500k")) {
                    this->baudRate0 = 0x00;
                    this->baudRate1 = 0x1C;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "400k")) {
                    this->baudRate0 = 0x80;
                    this->baudRate1 = 0xFA;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "250k")) {
                    this->baudRate0 = 0x01;
                    this->baudRate1 = 0x1C;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "200k")) {
                    this->baudRate0 = 0x81;
                    this->baudRate1 = 0xFA;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "125k")) {
                    this->baudRate0 = 0x03;
                    this->baudRate1 = 0x1C;
                } else if (std::equal(selectedBaudRate.begin(), selectedBaudRate.end(), "100k")) {
                    this->baudRate0 = 0x04;
                    this->baudRate1 = 0x1C;
                } else {
                    this->baudRate0 = 0x00;
                    this->baudRate1 = 0x14;
                }
                std::cout << "选择打开CAN模式: " << (int) openCanMode
                          << ", 波特率: <" << std::showbase << std::hex << (int) baudRate0 << ", " << (int) baudRate1
                          << ">"
                          << std::endl;
            }
    );

    // 连接打开设备按钮的点击事件
    connect(
            openDeviceButton,
            SIGNAL(clicked()),
            this,
            SLOT(UserOpenCaneDevice())
    );
    resize(960, 540);
}

unsigned int OpenCan::OpenCanDevice(
        bool unset_config = false,
        INIT_CONFIG init_config = {
                .AccCode = 0,
                .AccMask = 0xffffff,//不滤波
                .Filter = 0,
                .Timing0 =  0x00,    //波特率 500k
                .Timing1 =  0x1c,    //波特率 500k
                .Mode = 0            //正常模式
        }
) {
    // 0. 每次打开前，先关闭设备，避免出现打不开的情况
    CloseDevice(DeviceType, DeviceInd);

    // 1. 打开设备
    unsigned int status = OpenDevice(DeviceType, DeviceInd, 0);
    if (status != STATUS_OK) {
        std::cout << "打开设备失败" << std::endl;
        return status;
    }
    std::cout << "打开设备成功" << std::endl;

    // 2. 初始化 CAN1 设备
    if (unset_config) {// 用户没有主动设置，我们使用默认配置
        memset(&init_config, 0, sizeof(init_config));
        init_config.AccCode = 0;
        init_config.AccMask = 0xffffff; //不滤波
        init_config.Filter = 0;
        init_config.Timing0 = 0x00;     //波特率500k
        init_config.Timing1 = 0x1c;     //波特率 500k
        init_config.Mode = 0;           //正常模式
    }
    status = InitCAN(DeviceType, DeviceInd, CAN1, &init_config);
    if (status != STATUS_OK) {
        std::cout << "初始化通道失败" << std::endl;
        CloseDevice(DeviceType, DeviceInd);
        return status;
    }
    std::cout << "初始化CAN1通道成功: "
              << "波特率 = " << init_config.Timing0
              << ", 模式 = " << static_cast<int>(init_config.Mode) << std::endl;

    // 2.1. 开始 CAN1 设备
    status = StartCAN(DeviceType, DeviceInd, CAN1);
    if (status != STATUS_OK) {
        std::cout << "打开CAN1通道失败" << std::endl;
        CloseDevice(DeviceType, DeviceInd);
        return status;
    }
    std::cout << "打开CAN1通道成功: "
              << "波特率 = " << init_config.Timing0
              << ", 模式 = " << static_cast<int>(init_config.Mode) << std::endl;

    // 3. 初始化 CAN2 设备
    status = InitCAN(DeviceType, DeviceInd, CAN2, &init_config);
    if (status != STATUS_OK) {
        std::cout << "初始化CAN2通道失败" << std::endl;
        CloseDevice(DeviceType, DeviceInd);
        return status;
    }
    std::cout << "初始化CAN2通道成功: "
              << "波特率 = " << init_config.Timing1
              << ", 模式 = " << static_cast<int>(init_config.Mode) << std::endl;

    // 3.1. 开始 CAN2 设备
    status = StartCAN(DeviceType, DeviceInd, CAN2);
    if (status != STATUS_OK) {
        std::cout << "打开CAN2通道失败" << std::endl;
        CloseDevice(DeviceType, DeviceInd);
        return status;
    }
    std::cout << "打开CAN2通道成功: "
              << "波特率 = " << init_config.Timing1
              << ", 模式 = " << static_cast<int>(init_config.Mode) << std::endl;

    return STATUS_OK;
}

void OpenCan::UserOpenCaneDevice() {
    INIT_CONFIG init_config = {
            .AccCode = 0,
            .AccMask = 0xffffff,//不滤波
            .Filter = 0,
            .Timing0 = this->baudRate0,    //波特率500k
            .Timing1 = this->baudRate1,    //波特率 500k
            .Mode = this->openCanMode      //正常模式
    };
#if 1 // 打印当前配置
    std::cout << "INIT_CONFIG init_config = {" << std::endl;
    std::cout << "    .AccCode = " << std::showbase << std::hex << (int) init_config.AccCode << "," << std::endl;
    std::cout << "    .AccMask = " << std::showbase << std::hex << (int) init_config.AccMask << "," << std::endl;
    std::cout << "    .Filter  = " << std::showbase << std::hex << (int) init_config.Filter << "," << std::endl;
    std::cout << "    .Timing0 = " << std::showbase << std::hex << (int) init_config.Timing0 << "," << std::endl;
    std::cout << "    .Timing1 = " << std::showbase << std::hex << (int) init_config.Timing1 << "," << std::endl;
    std::cout << "    .Mode    = " << std::showbase << std::hex << (int) init_config.Mode << std::endl;
    std::cout << "};" << std::endl;
#endif
    int status = STATUS_OK;
    std::function<void(void)> pFunction = [this, &init_config, &status](void) -> void {
        status = OpenCanDevice(false, init_config);
    };
    std::thread thread(pFunction);
    thread.join();
#define TEST false
    if (TEST || status == STATUS_OK) {
        CommunityCan *communityCan;
        communityCan = new CommunityCan();
        communityCan->show();
    } else {// 模拟打开设备失败
        errorLabel->setText("打开设备失败，错误码：" + QString::number(status));
        errorLabel->setVisible(true);
    }
}

/**
 * 关闭窗口的回调
 *
 * @param event 回调事件
 */
void OpenCan::closeEvent(QCloseEvent *event) {
    // 窗口关闭时，我们关闭can设备，避免出现段错误
    CloseDevice(DeviceType, DeviceInd);
    QWidget::closeEvent(event);
}

